#ifndef CAP_CAP_H
#define CAP_CAP_H

#include <utils/list.h>
#include <utils/atomic.h>
#include <seminix/spinlock.h>
#include <cap/cap_typedef.h>
#include <cap/cap_desc.h>
#include <libseminix/types.h>

struct cnode;

#define CAP_TYPE_BITS   5
#define CAP_TYPE_SHIFT  ((sizeof(int)*8) - CAP_TYPE_BITS)
#define CAP_TYPE_MASK   BIT_GENMASK(CAP_TYPE_BITS)
#define CAP_TYPE_MAX    BIT(CAP_TYPE_BITS)
__static_assert(CAP_TYPE_MAX >= cap_count_max, "cap type: No space for cap_type bits field in cap flags");

typedef struct cap {
    unsigned long flags;

    struct cap *parent;
    struct list_head child;
    struct list_head list;

    /* 能力锁, 对能力的访问 create/dup/revoke/delete 均需要 lock 的保护 */
    spinlock_t  lock;

    atomic_t    refcount;

    int         index;
    struct cap_cnode  *cap_cnode;
    struct cap_rlimit *cap_rlimit;
} cap_t;

static inline int cap_get_cap_type(cap_t *cap)
{
    return (int)((cap->flags >> CAP_TYPE_SHIFT) & CAP_TYPE_MASK);
}

static inline void cap_set_cap_type(cap_t *cap, int type)
{
    cap->flags &= ~(CAP_TYPE_MASK << CAP_TYPE_SHIFT);
    cap->flags |= (type & CAP_TYPE_MASK) << CAP_TYPE_SHIFT;
}

/* flags */
#define CAP_CAN_DUP         0
#define CAP_CAN_MOVE        1
#define CAP_CAN_SEND        2
#define CAP_CAN_RECV        3
#define CAP_CAN_WRITE       4
#define CAP_CAN_CREATE      5
#define CAP_REVOCABLE       6
#define CAP_REMOVING        7
#define CAP_FROM_CNODE      8
#define CAP_FLAGS_MAX       9
__static_assert(CAP_FLAGS_MAX < CAP_TYPE_SHIFT, "cap flags: No space for flags bits field in cap flags");

static inline int cap_test_atomic(cap_t *cap, int bit)
{
    return test_bit(bit, &cap->flags);
}

static inline void cap_set_atomic(cap_t *cap, int bit)
{
    set_bit(bit, &cap->flags);
}

static inline void cap_clear_atomic(cap_t *cap, int bit)
{
    clear_bit(bit, &cap->flags);
}

#define TESTCAPFLAG(uname, lname)       \
static __always_inline int cap_##uname(cap_t *cap)  \
    { return cap_test_atomic(cap, CAP_##lname); }
#define SETCAPFLAG(uname, lname)        \
static __always_inline void cap_set_##uname(cap_t *cap) \
    { cap_set_atomic(cap, CAP_##lname); }
#define CLEARCAPFLAG(uname, lname)      \
static __always_inline void cap_clear_##uname(cap_t *cap) \
    { cap_clear_atomic(cap, CAP_##lname); }
#define CAPFLAG(uname, lname)       \
    TESTCAPFLAG(uname, lname)       \
    SETCAPFLAG(uname, lname)        \
    CLEARCAPFLAG(uname, lname)

CAPFLAG(can_dup, CAN_DUP)
CAPFLAG(can_move, CAN_MOVE)
CAPFLAG(can_send, CAN_SEND)
CAPFLAG(can_recv, CAN_RECV)
CAPFLAG(can_write, CAN_WRITE)
CAPFLAG(can_create, CAN_CREATE)
CAPFLAG(revocable, REVOCABLE)
CAPFLAG(removing, REMOVING)
CAPFLAG(from_cnode, FROM_CNODE)

struct cap_ops {
    cap_t *(*cap_create)(seminix_object_t *object);
    void (*cap_delete)(cap_t *cap);
    cap_t *(*cap_dup)(cap_t *cap);
    void  (*cap_complete_dup)(cap_t *parent, cap_t *new);
    void (*cap_revoke)(cap_t *cap);
    unsigned long (*cap_dup_rlimit)(cap_t *cap);
    unsigned long (*cap_create_rlimit)(seminix_object_t *object);
    unsigned long (*cap_delete_rlimit)(cap_t *cap);
};

cap_t *cap_create(cap_t *cap, int rights, seminix_object_t *object);
cap_t *cap_dup(cap_t *cap, int rights);
int cap_revoke(cap_t *parent, cap_t *cap);
int cap_delete(cap_t *parent, cap_t *cap);
unsigned long cap_dup_rlimit(cap_t *cap);
unsigned long cap_create_rlimit(seminix_object_t *object);
unsigned long cap_delete_rlimit(cap_t *cap);
static inline unsigned long cap_rlimit_down(cap_t *cap)
{
    if (cap_revocable(cap))
        return cap_dup_rlimit(cap);
    else
        return cap_delete_rlimit(cap);
}

static inline bool cap_is_parent(cap_t *parent, cap_t *cap)
{
    return cap->parent == parent;
}

static inline void capget(cap_t *cap)
{
    atomic_inc(&cap->refcount);
}

static inline bool capget_not_zero(cap_t *cap)
{
    return atomic_inc_not_zero(&cap->refcount);
}

void capput(cap_t *cap);

int object_to_cap_type(seminix_object_type_t object_type);

#define INIT_ROOT_CAP                                        \
{                                                            \
    .flags = cap_rlimit_cap << CAP_TYPE_SHIFT              | \
             BIT(CAP_CAN_DUP)  | BIT(CAP_CAN_MOVE)  | BIT(CAP_CAN_SEND)   | \
             BIT(CAP_CAN_RECV) | BIT(CAP_CAN_WRITE) | BIT(CAP_CAN_CREATE),  \
    .refcount = ATOMIC_INIT(1),                              \
    .parent = NULL,                                          \
    .child = LIST_HEAD_INIT(root_cap_rlimit.cap.child),      \
    .list = LIST_HEAD_INIT(root_cap_rlimit.cap.list),        \
    .lock = __SPIN_LOCK_UNLOCKED(root_cap_rlimit.cap.lock),  \
    .index = -1,                                             \
    .cap_cnode = NULL,                                       \
    .cap_rlimit = NULL,                                      \
}

#endif /* !CAP_CAP_H */
